﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.Security;
using System.Linq;
using axCommerce.Data;

namespace axCommerce.Membership.Provider
{
	public class AxRoleProvider : RoleProvider
	{
		private string _applicationName;
		public override string ApplicationName
		{
			get { return _applicationName; }
			set { _applicationName = value; }
		}

		public override void Initialize(string name, NameValueCollection config)
		{
			if (config == null)
				throw new ArgumentNullException("config");

			if (String.IsNullOrEmpty(name))
				name = "CustomRoleProvider";

			if (String.IsNullOrEmpty(config["description"]))
			{
				config.Remove("description");
				config.Add("description", "Custom Role Provider");
			}

			base.Initialize(name, config);

			_applicationName = GetConfigValue(config["applicationName"],
						  System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);

		}

		private string GetConfigValue(string configValue, string defaultValue)
		{
			if (String.IsNullOrEmpty(configValue))
				return defaultValue;

			return configValue;
		}

		public override void AddUsersToRoles(string[] emails, string[] roleNames)
		{
			foreach (string email in emails)
			{
				Account account = Account.SearchByEmail(email);
				if (account == null) continue;
				
				foreach (string rolename in roleNames)
				{
					AccessRole role = AccessRole.SearchByName(rolename);
					if (role == null) continue;
					
					bool bIsPermissionExists =
						account.Permissions.Where(permission => permission.AccessRoleId == role.AccessRoleId).Count() > 0;

					if (!bIsPermissionExists && account.AccountId.HasValue && role.AccessRoleId.HasValue)
					{
						new Permission(account.AccountId.Value, role.AccessRoleId.Value).Save();
					}
				}
			}
		}

		public override void CreateRole(string roleName)
		{
			CreateRole(roleName, null);
		}

		public void CreateRole(string roleName, string roleDescription)
		{
			if (!RoleExists(roleName))
			{
				new AccessRole
					{
						Name = roleName,
						Description = roleDescription
					}.Save();
			}
		}

		public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
		{
			AccessRole role = AccessRole.SearchByName(roleName);
			if(role != null)
			{
				role.MarkAsDeleted();
				return true;
			}
			return false;
		}

		public override string[] FindUsersInRole(string roleName, string usernameToMatch)
		{
			AccessRole role = AccessRole.SearchByName(roleName);

			return
				Account.GetAllAccounts().Where(account => account.Email.Equals(usernameToMatch, StringComparison.OrdinalIgnoreCase))
					.Where(account => account.Permissions.Any(permission => permission.AccessRoleId == role.AccessRoleId)).Select(
						account => account.Email).ToArray();
		}

		public override string[] GetAllRoles()
		{
			return AccessRole.GetAllRoles().Select(account => account.Name).ToArray();
		}

		public override string[] GetRolesForUser(string email)
		{
			Account account = Account.SearchByEmail(email);
			return
				account.Permissions.Select(
					permission => permission.AccessRoleId != null ? AccessRole.Get(permission.AccessRoleId.Value).Name : null).ToArray();
		}

		public override string[] GetUsersInRole(string roleName)
		{
			AccessRole role = AccessRole.SearchByName(roleName);

			var clearSiteUsers =
				Account.GetAllAccounts().Where(
					account => account.Permissions.Any(permission => permission.AccessRoleId == role.AccessRoleId)).Select(
						account => account.Email);

			return clearSiteUsers.ToArray();
		}

		public override bool IsUserInRole(string email, string roleName)
		{
			Account account = Account.SearchByEmail(email);
			AccessRole role = AccessRole.SearchByName(roleName);
			
			if (account != null && role != null)
			{
				return account.Permissions.Where(permission => permission.AccessRoleId == role.AccessRoleId).Count() > 0;
			}
			throw new Exception("Ошибка при проверке ролей пользователя");
		}

		public override void RemoveUsersFromRoles(string[] emails, string[] roleNames)
		{
			foreach (string email in emails)
			{
				Account account = Account.SearchByEmail(email);
				if (account != null)
				{
					foreach (string rolename in roleNames)
					{
						AccessRole role = AccessRole.SearchByName(rolename);
						if (role != null)
						{
							Permission accountPermission =
								account.Permissions.Where(permission => permission.AccessRoleId == role.AccessRoleId).FirstOrDefault();

							if (accountPermission != null)
							{
								accountPermission.MarkAsDeleted();
							}
						}
					}
				}
			}
		}

		public override bool RoleExists(string roleName)
		{
			return AccessRole.SearchByName(roleName) != null;
		}
	}
}
